<?php

/**
 * This file is part of the Nette Framework (http://nette.org)
 *
 * Copyright (c) 2004, 2011 David Grudl (http://davidgrudl.com)
 *
 * For the full copyright and license information, please view
 * the file license.txt that was distributed with this source code.
 */

namespace Nette\Config;

use Nette,
	Nette\Utils\Neon;



/**
 * Reading and writing INI files.
 *
 * @author     Ondrej Hubsch
 */
final class NeonAdapter implements IAdapter
{
	/** @var string  section inheriting separator (section < parent) */
	public static $sectionSeparator = ' < ';


	/**
	 * Static class - cannot be instantiated.
	 */
	final public function __construct()
	{
		throw new Nette\StaticClassException;
	}



	/**
	 * Reads configuration from NEON file.
	 * @param  string  file name
	 * @return array
	 * @throws Nette\InvalidStateException
	 */
	public static function load($file)
	{
		if (!is_file($file) || !is_readable($file)) {
			throw new Nette\FileNotFoundException("File '$file' is missing or is not readable.");
		}

		$neon = Neon::decode(file_get_contents($file));

		$separator = trim(self::$sectionSeparator);
		$data = array();
		foreach ($neon as $secName => $secData) {
			if ($secData === NULL) { // empty section
				$secData = array();
			}

			if (is_array($secData)) {
				// process extends sections like [staging < production]
				$parts = $separator ? explode($separator, $secName) : array($secName);
				if (count($parts) > 1) {
					$parent = trim($parts[1]);
					if (!isset($data[$parent]) || !is_array($data[$parent])) {
						throw new Nette\InvalidStateException("Missing parent section '$parent' in file '$file'.");
					}
					$secData = array_reverse(Nette\Utils\Arrays::mergeTree(array_reverse($secData, TRUE), array_reverse($data[$parent], TRUE)), TRUE);
					$secName = trim($parts[0]);
					if ($secName === '') {
						throw new Nette\InvalidStateException("Invalid empty section name in file '$file'.");
					}
				}
			}

			$data[$secName] = $secData;
		}

		return $data;
	}



	/**
	 * Write NEON file.
	 * @param  mixed
	 * @param  string  file
	 * @return void
	 */
	public static function save($config, $file)
	{
		if (!file_put_contents($file, "# generated by Nette\n\n" . Neon::encode($config, Neon::BLOCK))) {
			throw new Nette\IOException("Cannot write file '$file'.");
		}
	}

}
